package service

import (
	"crypto/rand"
	"encoding/hex"
	"errors"
	"fmt"
	"path/filepath"
	"strings"
	"time"

	"markedit/internal/model"

	"github.com/sirupsen/logrus"
	"gorm.io/gorm"
)

type UserFileService struct {
	db     *gorm.DB
	logger *logrus.Logger
}

func NewUserFileService(db *gorm.DB, logger *logrus.Logger) *UserFileService {
	return &UserFileService{
		db:     db,
		logger: logger,
	}
}

// CreateFile 创建文件
func (s *UserFileService) CreateFile(userID string, req *model.UserFileRequest) (*model.UserFile, error) {
	// 生成文件ID
	fileID, err := s.generateFileID()
	if err != nil {
		return nil, fmt.Errorf("生成文件ID失败: %v", err)
	}

	// 构建文件路径
	path, err := s.buildFilePath(userID, req.ParentID, req.Name)
	if err != nil {
		return nil, err
	}

	// 检查文件是否已存在
	var existingFile model.UserFile
	if err := s.db.Where("user_id = ? AND path = ?", userID, path).First(&existingFile).Error; err == nil {
		return nil, errors.New("文件已存在")
	}

	// 确定MIME类型
	mimeType := s.getMimeType(req.Name, req.IsFolder)

	// 创建文件记录
	file := &model.UserFile{
		ID:        fileID,
		UserID:    userID,
		Name:      req.Name,
		Path:      path,
		Content:   req.Content,
		Size:      int64(len(req.Content)),
		MimeType:  mimeType,
		IsFolder:  req.IsFolder,
		ParentID:  req.ParentID,
		CreatedAt: time.Now(),
		UpdatedAt: time.Now(),
	}

	if err := s.db.Create(file).Error; err != nil {
		return nil, fmt.Errorf("创建文件失败: %v", err)
	}

	s.logger.Infof("用户 %s 创建文件: %s", userID, path)
	return file, nil
}

// GetFile 获取文件
func (s *UserFileService) GetFile(userID, fileID string) (*model.UserFile, error) {
	var file model.UserFile
	if err := s.db.Where("id = ? AND user_id = ?", fileID, userID).First(&file).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("文件不存在")
		}
		return nil, fmt.Errorf("查询文件失败: %v", err)
	}
	return &file, nil
}

// GetFileByPath 根据路径获取文件
func (s *UserFileService) GetFileByPath(userID, path string) (*model.UserFile, error) {
	var file model.UserFile
	if err := s.db.Where("user_id = ? AND path = ?", userID, path).First(&file).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("文件不存在")
		}
		return nil, fmt.Errorf("查询文件失败: %v", err)
	}
	return &file, nil
}

// UpdateFile 更新文件
func (s *UserFileService) UpdateFile(userID, fileID string, content string) (*model.UserFile, error) {
	file, err := s.GetFile(userID, fileID)
	if err != nil {
		return nil, err
	}

	if file.IsFolder {
		return nil, errors.New("不能更新文件夹内容")
	}

	file.Content = content
	file.Size = int64(len(content))
	file.UpdatedAt = time.Now()

	if err := s.db.Save(file).Error; err != nil {
		return nil, fmt.Errorf("更新文件失败: %v", err)
	}

	s.logger.Infof("用户 %s 更新文件: %s", userID, file.Path)
	return file, nil
}

// DeleteFile 删除文件
func (s *UserFileService) DeleteFile(userID, fileID string) error {
	file, err := s.GetFile(userID, fileID)
	if err != nil {
		return err
	}

	// 如果是文件夹，递归删除所有子文件
	if file.IsFolder {
		if err := s.deleteChildrenRecursively(userID, fileID); err != nil {
			return fmt.Errorf("删除子文件失败: %v", err)
		}
	}

	// 删除文件本身
	if err := s.db.Delete(file).Error; err != nil {
		return fmt.Errorf("删除文件失败: %v", err)
	}

	s.logger.Infof("用户 %s 删除文件: %s", userID, file.Path)
	return nil
}

// RenameFile 重命名文件
func (s *UserFileService) RenameFile(userID, fileID, newName string) (*model.UserFile, error) {
	file, err := s.GetFile(userID, fileID)
	if err != nil {
		return nil, err
	}

	// 构建新路径
	newPath, err := s.buildFilePath(userID, file.ParentID, newName)
	if err != nil {
		return nil, err
	}

	// 检查新路径是否已存在
	var existingFile model.UserFile
	if err := s.db.Where("user_id = ? AND path = ? AND id != ?", userID, newPath, fileID).First(&existingFile).Error; err == nil {
		return nil, errors.New("目标文件名已存在")
	}

	// 更新文件信息
	oldPath := file.Path
	file.Name = newName
	file.Path = newPath
	file.UpdatedAt = time.Now()

	if err := s.db.Save(file).Error; err != nil {
		return nil, fmt.Errorf("重命名文件失败: %v", err)
	}

	// 如果是文件夹，需要更新所有子文件的路径
	if file.IsFolder {
		if err := s.updateChildrenPaths(userID, fileID, oldPath, newPath); err != nil {
			s.logger.Warnf("更新子文件路径失败: %v", err)
		}
	}

	s.logger.Infof("用户 %s 重命名文件: %s -> %s", userID, oldPath, newPath)
	return file, nil
}

// ListFiles 列出文件
func (s *UserFileService) ListFiles(userID, parentID string) ([]model.UserFileResponse, error) {
	var files []model.UserFile
	query := s.db.Where("user_id = ?", userID)
	
	if parentID == "" {
		query = query.Where("parent_id IS NULL OR parent_id = ''")
	} else {
		query = query.Where("parent_id = ?", parentID)
	}

	if err := query.Order("is_folder DESC, name ASC").Find(&files).Error; err != nil {
		return nil, fmt.Errorf("查询文件列表失败: %v", err)
	}

	var result []model.UserFileResponse
	for _, file := range files {
		fileResp := model.UserFileResponse{
			ID:        file.ID,
			Name:      file.Name,
			Path:      file.Path,
			Size:      file.Size,
			MimeType:  file.MimeType,
			IsFolder:  file.IsFolder,
			ParentID:  file.ParentID,
			CreatedAt: file.CreatedAt,
			UpdatedAt: file.UpdatedAt,
		}

		// 如果是文件夹，获取子文件
		if file.IsFolder {
			children, err := s.ListFiles(userID, file.ID)
			if err == nil {
				fileResp.Children = children
			}
		}

		result = append(result, fileResp)
	}

	return result, nil
}

// GetFileTree 获取文件树
func (s *UserFileService) GetFileTree(userID string) ([]model.UserFileResponse, error) {
	return s.ListFiles(userID, "")
}

// SearchFiles 搜索文件
func (s *UserFileService) SearchFiles(userID, keyword string) ([]model.UserFileResponse, error) {
	var files []model.UserFile
	if err := s.db.Where("user_id = ? AND (name LIKE ? OR content LIKE ?)", 
		userID, "%"+keyword+"%", "%"+keyword+"%").Find(&files).Error; err != nil {
		return nil, fmt.Errorf("搜索文件失败: %v", err)
	}

	var result []model.UserFileResponse
	for _, file := range files {
		result = append(result, model.UserFileResponse{
			ID:        file.ID,
			Name:      file.Name,
			Path:      file.Path,
			Size:      file.Size,
			MimeType:  file.MimeType,
			IsFolder:  file.IsFolder,
			ParentID:  file.ParentID,
			CreatedAt: file.CreatedAt,
			UpdatedAt: file.UpdatedAt,
		})
	}

	return result, nil
}

// buildFilePath 构建文件路径
func (s *UserFileService) buildFilePath(userID, parentID, fileName string) (string, error) {
	if parentID == "" {
		return "/" + fileName, nil
	}

	// 获取父文件夹
	var parentFile model.UserFile
	if err := s.db.Where("id = ? AND user_id = ? AND is_folder = ?", parentID, userID, true).First(&parentFile).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return "", errors.New("父文件夹不存在")
		}
		return "", fmt.Errorf("查询父文件夹失败: %v", err)
	}

	return filepath.Join(parentFile.Path, fileName), nil
}

// getMimeType 获取MIME类型
func (s *UserFileService) getMimeType(fileName string, isFolder bool) string {
	if isFolder {
		return "application/x-directory"
	}

	ext := strings.ToLower(filepath.Ext(fileName))
	switch ext {
	case ".md", ".markdown":
		return "text/markdown"
	case ".txt":
		return "text/plain"
	case ".html", ".htm":
		return "text/html"
	case ".css":
		return "text/css"
	case ".js":
		return "application/javascript"
	case ".json":
		return "application/json"
	case ".xml":
		return "application/xml"
	case ".pdf":
		return "application/pdf"
	case ".png":
		return "image/png"
	case ".jpg", ".jpeg":
		return "image/jpeg"
	case ".gif":
		return "image/gif"
	case ".svg":
		return "image/svg+xml"
	default:
		return "application/octet-stream"
	}
}

// deleteChildrenRecursively 递归删除子文件
func (s *UserFileService) deleteChildrenRecursively(userID, parentID string) error {
	var children []model.UserFile
	if err := s.db.Where("user_id = ? AND parent_id = ?", userID, parentID).Find(&children).Error; err != nil {
		return err
	}

	for _, child := range children {
		if child.IsFolder {
			if err := s.deleteChildrenRecursively(userID, child.ID); err != nil {
				return err
			}
		}
		if err := s.db.Delete(&child).Error; err != nil {
			return err
		}
	}

	return nil
}

// updateChildrenPaths 更新子文件路径
func (s *UserFileService) updateChildrenPaths(userID, parentID, oldParentPath, newParentPath string) error {
	var children []model.UserFile
	if err := s.db.Where("user_id = ? AND parent_id = ?", userID, parentID).Find(&children).Error; err != nil {
		return err
	}

	for _, child := range children {
		newPath := strings.Replace(child.Path, oldParentPath, newParentPath, 1)
		child.Path = newPath
		if err := s.db.Save(&child).Error; err != nil {
			return err
		}

		// 递归更新子文件夹的子文件
		if child.IsFolder {
			if err := s.updateChildrenPaths(userID, child.ID, oldParentPath, newParentPath); err != nil {
				return err
			}
		}
	}

	return nil
}

// generateFileID 生成文件ID
func (s *UserFileService) generateFileID() (string, error) {
	bytes := make([]byte, 16)
	if _, err := rand.Read(bytes); err != nil {
		return "", err
	}
	return fmt.Sprintf("file_%s", hex.EncodeToString(bytes)), nil
}